// This file is part of Blend2D project <https://blend2d.com>
//
// See blend2d.h or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib

#ifndef BLEND2D_API_H_INCLUDED
#define BLEND2D_API_H_INCLUDED

// This header can only be included by either <blend2d/blend2d.h> or by internal Blend2D headers. Prevent users
// including <blend2d/core/...> headers by accident and prevent not including "blend2d/core/api-build_p.h" during
// Blend2D compilation.
#if !defined(BLEND2D_H_INCLUDED) && !defined(BLEND2D_API_BUILD_P_H_INCLUDED) && !defined(__INTELLISENSE__)
  #pragma message("Include either <blend2d/blend2d.h> or <blen2d/blend2d-impl.h> to use Blend2D library")
#endif

#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>

#ifdef __cplusplus
  #include <type_traits>
#else
  #include <stdbool.h>
#endif

//! \mainpage Documentation Index
//!
//! Blend2D C and C++ API reference documentation generated by Doxygen.
//! \section main_topics Topics
//!
//! If you are new to Blend2D please checkout out the following links:
//!
//!   - <a href="getting-started.html">Getting Started</a> - introduction to Blend2D with code samples and outputs
//!   - <a href="build-instructions.html">Build Instructions</a> - instructions to build Blend2D with or without cmake
//!   - <a href="multithreaded-rendering.html">Multithreaded Rendering</a> - introduction to multi-threaded rendering
//!
//! \section main_overview Overview
//!
//! Blend2D API consists of enumerations, functions, structs, and C++ classes. Common concepts like enumerations and
//! POD structs are shared between C and C++. Some structs contain extra functionality like `BLSomething::reset()`
//! that is only available to C++ users, however, such functionality is only provided for convenience and doesn't
//! affect how Blend2D can be used from C.
//!
//! Blend2D C++ API is in fact build on top of the C API and all C++ functions are inlines that call C API without
//! any overhead. It would require double effort to document both C and C++ APIs separately so we have decided to
//! only document C++ API and to only list \ref bl_c_api "C API" for users that need it. The C API should be
//! straightforward and matches very well the C++ part.
//!
//!
//! \section main_groups Groups
//!
//! The documentation is split into the following groups:
//!
//! $$DOCS_GROUP_OVERVIEW$$
//!
//! \section main_important Important
//!
//! Doxygen has its limits, for example it sorts struct members in anonymous structs and unions and we haven't figured
//! out how to turn this feature off. This means that the order of members doesn't have to reflect the original struct
//! layout. Always double-check struct layout in case you plan to use a brace initialization of simple structs or in
//! case you are creating bindings.


//! \defgroup bl_globals Globals
//! \brief Global functions, constants, and classes used universally across the library.
//!
//! ### Result / Status Code
//!
//!   - \ref BLResult - a `uint32_t` typedef that represents a result returned by most C API and C++ API functions
//!   - \ref BLResultCode - an actual enumeration that describes known values that can be used by \ref BLResult
//!   - \ref BL_PROPAGATE() - macro that is used to propagate (return) a non-successful result from a function
//!
//! ### Types
//!
//!   - \ref BLTag - tag is a 32-bit value representing 4 ASCII characters, used by PNG and OpenType at the moment
//!   - \ref BLUniqueId - unique identifier is a 64-bit value, which must be unique for each domain where used
//!   - \ref BLUnknown - a `void` type, used in few special places
//!
//! ### Function Types
//!
//!   - \ref BLDebugMessageSinkFunc - a debug sink, can be used for logging purposes
//!
//! ### Constants
//!
//!   - \ref BLByteOrder - byte order
//!   - \ref BLDataAccessFlags - provides a type of data access (read, write, or both)
//!   - \ref BLDataSourceType - provides a type of a data source (memory, file, etc...)
//!   - \ref BLModifyOp - modification operation
//!   - \ref BLBooleanOp - boolean operation


//! \defgroup bl_containers Containers
//! \brief Containers and views used by Blend2D.
//!
//! Blend2D needs certain containers to function, but it cannot use containers from a C++ standard library because it
//! provides both C-API and C-ABI. In addition, the underlying representation of all classes that inherit from \ref
//! BLObjectCore need to provide reference counting, even for containers, so they can be shared across threads without
//! requiring to do any extra work by Blend2D users.
//!
//! In addition, Blend2D embraces small data optimization (often described as SSO - small string optimization), which
//! is utilized by \ref BLString, \ref BLArray, \ref BLBitArray, and other specialized containers.
//!
//! ### Views & Common Types
//!
//!   - \ref BLArrayView<T> - read-only view of an array (any array, not just \ref BLArray<T>)
//!   - \ref BLStringView - read-only view of a string, the view doesn't have to be null terminated
//!   - \ref BLRange - start/end range, which can be used with sequential containers
//!
//! ### Sequential Containers
//!
//!   - \ref BLArray<T> - growable array of T elements. Can hold both primitive types and Blend2D objects
//!     - \ref BLArrayCore - C API type representing \ref BLArray<T>
//!
//!   - \ref BLString - 8-bit null terminated string, usually UTF-8 encoded, but it's not a requirement
//!     - \ref BLStringCore - C API type representing \ref BLString
//!
//! ### Bit Containers
//!
//!   - \ref BLBitArray - a dense bit-array (stores bits starting from 0 to size, sequentially)
//!     - \ref BLBitArrayCore - C API type representing \ref BLBitArray
//!
//!   - \ref BLBitSet - a sparse bit array that can represent sparse/dense bits and range of bits (will be deprecated)
//!     - \ref BLBitSetCore - C API type representing \ref BLBitSet
//!     - \ref BLBitSetSegment - segment used by \ref BLBitSet
//!     - \ref BLBitSetData - data view used by \ref BLBitSet


//! \defgroup bl_geometry Geometries
//! \brief Geometries, paths, and transformations.
//!
//! Blend2D offers various geometry structures and objects that can be used with either \ref BLPath for path building or
//! \ref BLContext for rendering. In general there are two categories - \ref BLPath, which specifies a 2D path composed
//! of path segments, and lightweight geometries such as \ref BLRect, \ref BLRoundRect, etc... which are only described
//! by a trivial C/C++ struct.
//!
//! ### Paths
//!
//!   - \ref BLPath - path container
//!     - \ref BLPathCore - C API type representing \ref BLPath
//!     - \ref BLPathCmd - path command specifies the type of a path segment withing \ref BLPath
//!     - \ref BLPathFlags - flags associated with \ref BLPath
//!     - \ref BLPathReverseMode - reverse mode accepted by  \ref BLPath::add_reversed_path()
//!     - \ref BLPathView - view providing all necessary variables to inspect and iterate a \ref BLPath
//!
//! ### Path Operations
//!
//!   - \ref BLStrokeOptions - holds stroking options
//!     - \ref BLStrokeOptionsCore - C API type representing \ref BLStrokeOptions
//!   - \ref BLOffsetMode - path offsetting mode
//!   - \ref BLFlattenMode - path flattening mode
//!   - \ref BLStrokeCap - stroke cap option
//!   - \ref BLStrokeCapPosition - stroke cap position (can be specified separately)
//!   - \ref BLStrokeJoin - stroke join option
//!   - \ref BLStrokeTransformOrder - the order of a transformation when rendering a stroked path or geometry
//!
//! ### Lightweight Geometries and Structs
//!
//!   - \ref BLPoint - 2D point composed of `[x, y]` values (64-bit floats)
//!   - \ref BLPointI - 2D point composed of `[x, y]` values (32-bit integers)
//!   - \ref BLSize - 2D size composed of `[w, h]` values (64-bit floats)
//!   - \ref BLSizeI - 2D size composed of `[w, h]` values (32-bit integers)
//!   - \ref BLBox - 2D rectangular area composed of `[x0, y0, x1, y1]` values (64-bit floats)
//!   - \ref BLBoxI - 2D rectangular area composed of `[x0, y0, x1, y1]` values (32-bit integers)
//!   - \ref BLRect - 2D rectangular area composed of `[x, y, w, h]` values (64-bit floats)
//!   - \ref BLRectI - 2D rectangular area composed of `[x, y, w, h]` values (32-bit integers)
//!   - \ref BLRoundRect - rounded rectangle within `[x, y, w, h]` with radius `[rx, ry]` (64-bit floats)
//!   - \ref BLCircle - circle at `[cx, cy]` with radius `r` (64-bit floats)
//!   - \ref BLEllipse - ellipse at `[cx, cy]` with radius `[rx, ry]` (64-bit floats)
//!   - \ref BLArc - arc at `[cx, cy]` with radius `[rx, ry]` and `start` + `sweep` values  (64-bit floats)
//!   - \ref BLLine - line segment from `[x0, y0]` to `[x1, y1]` (64-bit floats)
//!   - \ref BLTriangle - triangle having `[x0, y0]`, `[x1, y1]`, and `[x2, y2]` vertices (64-bit floats)
//!
//! ### Geometry Constants
//!
//!   - \ref BLGeometryDirection - specifies a direction
//!   - \ref BLGeometryType - specifies a type of a geometry argument (low-level)
//!   - \ref BLFillRule - specifies a fill rule (used by both \ref BLPath and \ref BLContext)
//!   - \ref BLHitTest - specifies a result of hit-testing
//!
//! ### Transformations
//!
//!   - \ref BLMatrix2D - 2D transformation matrix (affine)
//!     - \ref BLTransformOp - transformation operation (low-level)
//!     - \ref BLTransformType - transformation type


//! \defgroup bl_imaging Imaging
//! \brief Images and image codecs.
//!
//! Provides image container (\ref BLImage), image codecs (\ref BLImageCodec), and pixel conversion (\ref BLPixelConverter).
//!
//! ### Images
//!
//!   - \ref BLImage - image container that holds pixel data
//!     - \ref BLImageCore - C API type representing \ref BLImage
//!     - \ref BLImageData - pixel data and additional attributes
//!     - \ref BLImageInfo - image information data
//!     - \ref BLImageInfoFlags - image information flags
//!     - \ref BLImageScaleFilter - image scaling filters
//!
//! ### Image Codecs
//!
//!   - \ref BLImageCodec - image codec
//!     - \ref BLImageCodecCore - C API type representing \ref BLImageCodec
//!     - \ref BLImageCodecFeatures - image codec feature flags
//!
//!   - \ref BLImageDecoder - image decoder
//!     - \ref BLImageDecoderCore - C API type representing \ref BLImageDecoder
//!
//!   - \ref BLImageEncoder - image encoder
//!     - \ref BLImageEncoderCore - C API type representing \ref BLImageEncoder
//!
//! ### Pixel Format
//!
//!   - \ref BLFormat - pixel format
//!   - \ref BLFormatFlags - pixel format flags
//!   - \ref BLFormatInfo - pixel format information
//!
//!
//! ### Pixel Conversion
//!
//!   - \ref BLPixelConverter - pixel converter
//!     - \ref BLPixelConverterCore - C API type representing \ref BLPixelConverter
//!     - \ref BLPixelConverterCreateFlags - flags that can be used when creating a pixel converter
//!     - \ref BLPixelConverterOptions - pixel conversion options


//! \defgroup bl_styling Styling
//! \brief Colors, gradients, and patterns.
//!
//! Styling provides various classes that represent colors, gradients, and patterns. While colors are used universally
//! across the library (not just as styles), gradients and patterns are always used as fill or stroke styles.
//!
//! ### Colors
//!
//!   - \ref BLRgba - RGBA color specified as 32-bit floating point value per channel
//!   - \ref BLRgba32 - RGBA color specified as 8-bit value per channel as `0xAARRGGBB`
//!   - \ref BLRgba64 - RGBA color specified as 16-bit value per channel as `0xAAAARRRRGGGGBBBB`
//!   - (please note that the order if bytes in \ref BLRgba32 and \ref BLRgba64 is ARGB (from MSB to LSB) for
//!     compatibility with other libraries and common representations)
//!
//! ### Gradients
//!
//!   - \ref BLGradient - container that holds gradient values and stops
//!     - \ref BLGradientCore - C API type representing \ref BLGradient
//!     - \ref BLGradientStop - associates a color with offset (from 0.0 to 1.0)
//!     - \ref BLGradientType - describes a gradient type
//!     - \ref BLGradientValue - index of a gradient value (overlaps between various gradient types)
//!     - \ref BLGradientQuality - describes a gradient quality
//!     - \ref BLExtendMode - specifies a gradient extend mode (only simple extend modes can be used with gradients)
//!     - \ref BLLinearGradientValues - values describing a linear gradient
//!     - \ref BLRadialGradientValues - values describing a radial gradient
//!     - \ref BLConicGradientValues - values describing a conic gradient
//!
//! ### Patterns
//!
//!   - \ref BLPattern - represents a pattern
//!     - \ref BLPatternCore - C API type representing \ref BLPattern
//!     - \ref BLPatternQuality - describes a pattern quality
//!     - \ref BLExtendMode - specifies a pattern extend mode (all extend modes can be used with patterns)
//!
//! ### Variant
//!
//!   - \ref BLVar - variant type can be used to hold any style and then passed to the rendering context


//! \defgroup bl_text Text
//! \brief Fonts & Text support.
//!
//! ### Glyph Containers & Processing
//!
//!   - \ref BLGlyphBuffer - holds glyphs and additional metadata
//!     - \ref BLGlyphBufferCore - C API type representing \ref BLGlyphBuffer
//!     - \ref BLGlyphBufferImpl - underlying representation of \ref BLGlyphBuffer
//!
//!   - \ref BLGlyphRun - provides a glyph run data
//!     - \ref BLGlyphRunFlags - flags used by \ref BLGlyphRun
//!     - \ref BLGlyphRunIterator - iterates a \ref BLGlyphRun
//!
//!   - \ref BLGlyphId - a type representing a single glyph (32-bit value)
//!   - \ref BLGlyphInfo - glyph information used by \ref BLGlyphBuffer and \ref BLGlyphRun
//!   - \ref BLGlyphMappingState - information accumulated during mapping characters to glyphs
//!   - \ref BLGlyphPlacement - glyph placement used by \ref BLGlyphBuffer and \ref BLGlyphRun
//!   - \ref BLGlyphPlacementType - glyph placement used \ref BLGlyphBuffer and \ref BLGlyphRun
//!   - \ref BLGlyphOutlineSinkInfo - additional information passed to a callback by \ref BLFont::get_glyph_outlines()
//!     and \ref BLFont::get_glyph_run_outlines()
//!
//! ### Fonts
//!
//!   - \ref BLFont - represents a displayable font (having size, font properties, and variations configured)
//!     - \ref BLFontCore - C API type representing \ref BLFont
//!     - \ref BLFontMatrix - a simple matrix that can be used to transform a font, used by \ref BLFont
//!     - \ref BLFontMetrics - font metrics, used by \ref BLFont
//!     - \ref BLFontStretch - font stretch property, used by \ref BLFont
//!     - \ref BLFontStyle - font style property, used by \ref BLFont
//!     - \ref BLFontWeight - font weight property, used by \ref BLFont
//!
//!   - \ref BLFontData - provides font data that can be used by \ref BLFont and \ref BLFontFace
//!     - \ref BLFontDataCore - C API type representing \ref BLFontData
//!     - \ref BLFontDataFlags - Flags used by \ref BLFontData
//!     - \ref BLFontTable - represents a TrueType/OpenType table identified by a \ref BLTag
//!
//!   - \ref BLFontFace - represents a font face (OpenType file loaded from file or memory)
//!     - \ref BLFontFaceCore - C API type representing \ref BLFontFace
//!     - \ref BLFontFaceInfo - font face information, used by \ref BLFontFace
//!     - \ref BLFontFaceFlags - flags used by \ref BLFontFace
//!     - \ref BLFontFaceDiagFlags - diagnostic flags used by \ref BLFontFace
//!     - \ref BLFontFaceType - type of a font face, provided by \ref BLFontFace
//!     - \ref BLFontDesignMetrics - design font metrics, used by \ref BLFontFace
//!     - \ref BLFontOutlineType - type of outlines used by a font, used by \ref BLFontFace
//!     - \ref BLFontPanoseInfo - panose information, provided by \ref BLFontFace
//!     - \ref BLFontStringId - identifier of a string stored in a font face, used by \ref BLFontFace
//!     - \ref BLFontCoverageInfo - unicode coverage bits, provided by \ref BLFontFace
//!     - \ref BLFontCoverageGroup - meaning of unicode coverage bits of \ref BLFontCoverageInfo
//!
//!   - \ref BLFontFeatureSettings - provides feature settings of a \ref BLFont
//!     - \ref BLFontFeatureSettingsCore - C API type representing \ref BLFontFeatureSettings
//!     - \ref BLFontFeatureSettingsView - view of \ref BLFontFeatureSettings
//!     - \ref BLFontFeatureItem - associates a font feature tag (\ref BLTag) with a value
//!
//!   - \ref BLFontVariationSettings - provides variation settings of a \ref BLFont
//!     - \ref BLFontVariationSettingsCore - C API type representing \ref BLFontVariationSettings
//!     - \ref BLFontVariationSettingsView - view of \ref BLFontVariationSettings
//!     - \ref BLFontVariationItem - associates a font variation tag (\ref BLTag) with a value
//!
//! ### Font Management
//!
//!   - \ref BLFontManager - simple font management that can store and query \ref BLFontFace instances
//!     - \ref BLFontManagerCore - C API type representing \ref BLFontManager
//!     - \ref BLFontQueryProperties - font query properties, used by \ref BLFontManager
//!
//! ### Text
//!
//!   - \ref BLOrientation - text or glyph run orientation
//!   - \ref BLTextDirection - specifies text direction
//!   - \ref BLTextEncoding - specifies text encoding
//!   - \ref BLTextMetrics - metrics of a whole text run

//! \defgroup bl_rendering Rendering
//! \brief 2D rendering context API, structures, and constants.
//!
//! ### Rendering Context
//!
//!   - \ref BLContext - a 2D rendering context
//!     - \ref BLContextCore - C API type representing \ref BLContext
//!     - \ref BLContextType - rendering context type
//!     - \ref BLContextCookie - cookie can be used with \ref BLContext::save() and \ref BLContext::restore()
//!     - \ref BLContextCreateInfo - additional options that can be used when creating a rendering context
//!     - \ref BLContextCreateFlags - flags that can be used by \ref BLContextCreateInfo
//!     - \ref BLContextErrorFlags - accumulated error flags during the lifetime of a rendering context
//!     - \ref BLContextFlushFlags - flags that can be passed to \ref BLContext::flush()
//!     - \ref BLContextHint - rendering hint
//!     - \ref BLContextHints - all rendering hints in a single struct
//!     - \ref BLContextStyleSlot - style slot (either fill or stroke)
//!     - \ref BLContextStyleSwapMode - style swap mode (how to swap a fill and stroke styles)
//!     - \ref BLContextStyleTransformMode - style transform mode (how to combine with existing transform)
//!     - \ref BLContextRenderTextOp - type of a text rendering operation (low-level)
//!
//!     - \ref BLClipMode - clip mode
//!     - \ref BLCompOp - composition operator
//!     - \ref BLRenderingQuality - rendering quality (aliased rendering or the quality of anti-aliasing)


//! \defgroup bl_runtime Runtime
//! \brief Interaction with Blend2D runtime.


//! \defgroup bl_filesystem Filesystem
//! \brief Filesystem utilities.
//!
//! Blend2D doesn't do much with filesystem, however, since the library provides API for loading and saving raster
//! images and for loading font files, it internally needs a lightweight filesystem access. The API is also provided
//! for users that would like to use a very simple API to access a filesystem.
//!
//! ### File
//!
//!   - \ref BLFile - a lightweight non-shareable file API that uses a system file descriptor API where possible.
//!     - \ref BLFileCore - C API type representing \ref BLFile
//!     - \ref BLFileOpenFlags - flags used by \ref BLFile::open() function
//!     - \ref BLFileReadFlags - flags used when reading whole files by \ref BLFileSystem::read_file()
//!     - \ref BLFileSeekType - flags used by \ref BLFile::seek() function
//!
//! ### Filesystem
//!
//!   - \ref BLFileSystem - filesystem utilities
//!     - \ref BLFileInfo - file information (retrieved either by calling `stat()` or a similar function under Windows)
//!     - \ref BLFileInfoFlags - flags used by \ref BLFileInfo


//! \defgroup bl_miscellaneous Miscellaneous
//! \brief Miscellaneous and uncategorized API.
//!
//! ### Random
//!
//!   - \ref BLRandom - pseudo random number generator

//! \defgroup bl_impl Impl API
//! \brief API required for extending Blend2D functionality.
//!
//! Everything that is part of this group requires `<blend2d-impl.h>` to be
//! included before the use as this API is only for users that extend Blend2D.


//! \defgroup bl_macros Macros
//! \brief Preprocessor macros and compile-time constants.


//! \defgroup bl_c_api C API
//! \brief Blend2D C API structs and functions exported as `extern "C"` (C API).
//!
//! We do not document most C API functions as they are called from C++ wrappers, which are documented and should be
//! used as a reference. The most important thing in using C API is to understand how lifetime of instances is managed.
//!
//! Each type that requires initialization provides `bl[...]Init`, 'bl[...]Destroy', and `bl[...]Reset` C API functions.
//! Init/Destroy are called by C++ constructors and destructors on C++ side and must be used the same way by C users.
//! Although these functions return \ref BLResult it's guaranteed the result is always \ref BL_SUCCESS - the return
//! value is only provided for consistency and possible tail calling.
//!
//! The following example should illustrate how `Init` and `Destroy` works:
//!
//! ```
//! BLImageCore img;
//!
//! // Initializes the BLImage object, always succeeds.
//! bl_image_init(&img);
//!
//! // Creates image data, note how it's called on an already initialized object.
//! bl_image_create(&img, 128, 128, BL_FORMAT_PRGB32);
//!
//! // Destroys the BLImage object, always succeeds.
//! bl_image_destroy(&img);
//! ```
//!
//! Some init functions may provide shortcuts for the most used scenarios that
//! merge initialization and resource allocation into a single function:
//!
//! ```
//! BLImageCore img;
//!
//! // Combines bl_image_init() with bl_image_create().
//! bl_image_init_as(&img, 128, 128, BL_FORMAT_PRGB32);
//!
//! // Destroys the data, doesn't have to be called if bl_image_init_as() failed.
//! bl_image_destroy(&img);
//! ```
//!
//! It's worth knowing that default initialization in Blend2D costs nothing and no resources are allocated, thus
//! initialization never fails and in theory default initialized objects don't have to be destroyed as they don't
//! hold any data that would have to be deallocated (however never do that in practice).
//!
//! There is a distinction between 'destroy()' and 'reset()' functionality. Destroy would destroy the object and
//! put it into a non-reusable state. Thus if the object is used by accident it should crash on null-pointer access.
//! On the contrary, resetting the object with 'reset()' explicitly states that the instance will be reused so
//! 'reset()' basically destroys the object and puts it into its default constructed state for further use. This
//! means that it's not needed to explicitly call 'destroy()' on instance that was reset, and it also is not needed
//! for a default constructed instance. However, we recommend to not count on this behavior and to always properly
//! initialize and destroy Blend2D objects.
//!
//! The following example should explain how init/reset can avoid destroy:
//!
//! ```
//! BLImageCore img;
//!
//! // Now image is default constructed/initialized. if you did just this and abandon it then no resources will
//! // be leaked as default construction is not allocating any resources nor increasing any reference counters.
//! bl_image_init(&img);
//!
//! // Now image will have to dynamically allocate some memory to store pixel data. If this succeeds the image
//! // will have to be explicitly destroyed when it's no longer needed to release the associated data it holds.
//! BLResult result = bl_image_create(&img, 128, 128, BL_FORMAT_PRGB32);
//!
//! // If `bl_image_create()` failed it leaves the object in the state it was prior to the call. Most of API calls
//! // in Blend2D behave like this (it's transactional). This means that if the call failed the `img` would still
//! // be default constructed and the function can simply return without leaking any resources. In C++ API the
//! // compiler would emit a call to `bl_image_destroy()` implicitly, but that's just how RAII works.
//! if (result != BL_SUCCESS)
//!   return result;
//!
//! // Resetting image would destroy its data and make it default constructed.
//! bl_image_reset(&img);
//!
//! // The instance is valid after `reset()` - it's now a default constructed instance as created by `bl_image_init()`.
//! printf("%p", img.impl);
//!
//! // Calling `bl_image_destroy()` would make the instance invalid.
//! bl_image_destroy(&img);
//!
//! // Calling any method except initialization such as `bl_image_init()` on invalid instance is UNDEFINED BEHAVIOR!
//! bl_image_create(&img, 128, 128, BL_FORMAT_PRGB32); // Can crash, can corrupt memory, can succeed, never do that!
//! ```


//! \cond INTERNAL

//! \defgroup blend2d_internal Internal
//!
//! \brief Internal API.


//! \defgroup blend2d_codec_impl Codecs
//!
//! \brief Codecs implementation.


//! \defgroup blend2d_raster_engine_impl Raster
//!
//! \brief Raster rendering context.


//! \defgroup blend2d_pipeline_jit JIT pipeline compiler
//!
//! \brief JIT pipeline compiler.


//! \defgroup blend2d_pipeline_reference Reference pipeline implementation
//!
//! \brief Reference pipeline implementation.


//! \defgroup blend2d_opentype_impl OpenType
//!
//! \brief OpenType implementation.

//! \endcond

// Blend2D Version
// ===============

//! \addtogroup bl_macros
//! \{

//! \name Version Information
//! \{

//! Makes a version number representing a `MAJOR.MINOR.PATCH` combination.
#define BL_MAKE_VERSION(MAJOR, MINOR, PATCH) (((MAJOR) << 16) | ((MINOR) << 8) | (PATCH))

//! Blend2D library version.
#define BL_VERSION BL_MAKE_VERSION(0, 21, 2)

//! \}
//! \}

// Build Type
// ==========

//! \cond INTERNAL

// These definitions can be used to enable static library build. Embed is used when Blend2D's source code is embedded
// directly in another project, implies static build as well.
//
// #define BL_STATIC                // Blend2D is a statically linked library.

// These definitions control the build mode and tracing support. The build mode should be auto-detected at compile
// time, but it's possible to override it in case that the auto-detection fails.
//
// Tracing is a feature that is never compiled by default and it's only used to debug Blend2D itself.
//
// #define BL_BUILD_DEBUG           // Define to enable debug-mode.
// #define BL_BUILD_RELEASE         // Define to enable release-mode.

// Detect BL_BUILD_DEBUG and BL_BUILD_RELEASE if not defined.
#if !defined(BL_BUILD_DEBUG) && !defined(BL_BUILD_RELEASE)
  #ifndef NDEBUG
    #define BL_BUILD_DEBUG
  #else
    #define BL_BUILD_RELEASE
  #endif
#endif

//! \endcond

// Public Macros
// =============

//! \addtogroup bl_macros
//! \{

//! \name Target Information
//! \{

//! \def BL_BYTE_ORDER
//!
//! A compile-time constant (macro) that defines byte-order of the target. It can be either `1234` for little-endian
//! targets or `4321` for big-endian targets. Blend2D uses this macro internally, but it's also available to end
//! users as sometimes it could be important for deciding between pixel formats or other important details.
#if (defined(__ARMEB__)) || (defined(__MIPSEB__)) || \
    (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
  #define BL_BYTE_ORDER 4321
#else
  #define BL_BYTE_ORDER 1234
#endif

//! \}

//! \name Decorators
//! \{

//! \def BL_API
//!
//! A base API decorator that marks functions and variables exported by Blend2D.
#if !defined(BL_STATIC)
  #if defined(_WIN32) && (defined(_MSC_VER) || defined(__MINGW32__))
    #if defined(BL_BUILD_EXPORT)
      #define BL_API __declspec(dllexport)
    #else
      #define BL_API __declspec(dllimport)
    #endif
  #elif defined(_WIN32) && defined(__GNUC__)
    #if defined(BL_BUILD_EXPORT)
      #define BL_API __attribute__((dllexport))
    #else
      #define BL_API __attribute__((dllimport))
    #endif
  #elif defined(__GNUC__)
    #define BL_API __attribute__((__visibility__("default")))
  #endif
#endif

#ifndef BL_API
  #define BL_API
#endif

//! \def BL_CDECL
//!
//! Calling convention used by all exported functions and function callbacks. If you pass callbacks to Blend2D it's
//! strongly advised to decorate the callback explicitly as some compilers provide a way of overriding a global
//! calling convention (like __vectorcall on Windows platform), which would break the use of such callbacks.
#if defined(__GNUC__) && defined(__i386__) && !defined(__x86_64__)
  #define BL_CDECL __attribute__((__cdecl__))
#elif defined(_MSC_VER)
  #define BL_CDECL __cdecl
#else
  #define BL_CDECL
#endif

//! \def BL_INLINE
//!
//! Marks functions that should always be inlined.
#if defined(__GNUC__)
  #define BL_INLINE inline __attribute__((__always_inline__))
#elif defined(_MSC_VER)
  #define BL_INLINE __forceinline
#else
  #define BL_INLINE inline
#endif

//! \def BL_INLINE_NODEBUG
//!
//! The same as \ref BL_INLINE possibly combined with `__attribute__((artificial))` or `__attribute__((nodebug))`
//! if the compiler supports any of them.
//!
//! The purpose of this macro is to tell the compiler that the function should not need debugging, thus the debug
//! information can be omitted completely. Blend2D uses tris decorator to decorate C++ inline functions that either
//! call C API or that are trivial to improve debugging experience of some tiny abstractions.
#if defined(__clang__)
  #define BL_INLINE_NODEBUG inline __attribute__((__always_inline__, __nodebug__))
#elif defined(__GNUC__)
  #define BL_INLINE_NODEBUG inline __attribute__((__always_inline__, __artificial__))
#else
  #define BL_INLINE_NODEBUG BL_INLINE
#endif

#define BL_INLINE_CONSTEXPR constexpr BL_INLINE_NODEBUG

//! \def BL_NORETURN
//!
//! Function attribute used by functions that never return (that terminate the process). This attribute is used
//! only once by \ref bl_runtime_assertion_failure() function, which is only used when assertions are enabled. This
//! macro should be considered internal and it's not designed for Blend2D users.
#if defined(__GNUC__)
  #define BL_NORETURN __attribute__((__noreturn__))
#elif defined(_MSC_VER)
  #define BL_NORETURN __declspec(noreturn)
#else
  #define BL_NORETURN
#endif

//! \def BL_NOEXCEPT_C
//!
//! Defined to `noexcept` in C++ mode and nothing in C mode. This is used to mark Blend2D C API, which is `noexcept`
//! by design.
#if defined(__cplusplus)
  #define BL_NOEXCEPT_C noexcept
#else
  #define BL_NOEXCEPT_C
#endif

//! \def BL_PURE
//!
//! Function attribute that describes functions that have no side effects. The macro expands to
//! `__attribute__((__pure__))` when compiling with GCC or Clang, otherwise it expands to nothing.
#if defined(__GNUC__)
  #define BL_PURE __attribute__((__pure__))
#else
  #define BL_PURE
#endif

//! \def BL_ALIGN_TYPE(TYPE, ALIGNMENT)
//!
//! Defines a type with a particular alignment, avoiding the use of alignas() as some compilers
//! have a buggy implementation and restrict alignas() more than a compiler specific attribute.
#if defined(__GNUC__)
  #define BL_ALIGN_TYPE(TYPE, ALIGNMENT) __attribute__((__aligned__(ALIGNMENT))) TYPE
#elif defined(_MSC_VER)
  #define BL_ALIGN_TYPE(TYPE, ALIGNMENT) __declspec(align(ALIGNMENT)) TYPE
#else
  #define BL_ALIGN_TYPE(TYPE, ALIGNMENT) TYPE
#endif

//! \}

//! \name Assumptions
//! \{

//! \def BL_ASSUME(...)
//!
//! Macro that tells the C/C++ compiler that the expression `...` evaluates to true. This macro is only used by few
//! places and should be considered internal as you shouldn't need it when using Blend2D library.
#if defined(__clang__)
  #define BL_ASSUME(...) __builtin_assume(__VA_ARGS__)
#elif defined(__GNUC__) && __GNUC__ >= 13
  #define BL_ASSUME(...) __attribute__((__assume__(__VA_ARGS__)))
#elif defined(__GNUC__)
  #define BL_ASSUME(...) do { if (!(__VA_ARGS__)) __builtin_unreachable(); } while (0)
#elif defined(_MSC_VER)
  #define BL_ASSUME(...) __assume(__VA_ARGS__)
#else
  #define BL_ASSUME(...) (void)0
#endif

//! \def BL_LIKELY(...)
//!
//! A condition is likely.

//! \def BL_UNLIKELY(...)
//!
//! A condition is unlikely.

#if defined(__GNUC__)
  #define BL_LIKELY(...) __builtin_expect(!!(__VA_ARGS__), 1)
  #define BL_UNLIKELY(...) __builtin_expect(!!(__VA_ARGS__), 0)
#else
  #define BL_LIKELY(...) (__VA_ARGS__)
  #define BL_UNLIKELY(...) (__VA_ARGS__)
#endif

//! \}

//! \name Debugging and Error Handling
//! \{

//! \def BL_ASSERT(EXP)
//!
//! Run-time assertion executed in debug builds.
#ifdef BL_BUILD_DEBUG
  #define BL_ASSERT(EXP)                                                      \
    do {                                                                      \
      if (BL_UNLIKELY(!(EXP))) {                                              \
        bl_runtime_assertion_failure(__FILE__, __LINE__, #EXP);                  \
      }                                                                       \
    } while (0)
#else
  #define BL_ASSERT(EXP) ((void)0)
#endif

//! Executes the code within the macro, which is expected to provide a \ref BLResult, which is returned in case that it
//! is not successful (not equal to \ref BL_SUCCESS). This macro is heavily used across the library for error handling
//! and it's also exposed to end users in case they find comfortable using the same error handling technique to handle
//! errors returned by Blend2D or user code returning \ref BLResult.
#define BL_PROPAGATE(...)                                                     \
  do {                                                                        \
    BLResult result_to_propagate = (__VA_ARGS__);                               \
    if (BL_UNLIKELY(result_to_propagate)) {                                     \
      return result_to_propagate;                                               \
    }                                                                         \
  } while (0)

//! \}

//! \name Utilities
//! \{

//! Creates a 32-bit tag (uint32_t) from the given `A`, `B`, `C`, and `D` values.
#define BL_MAKE_TAG(A, B, C, D) ((BLTag)(((BLTag)(A) << 24) | ((BLTag)(B) << 16) | ((BLTag)(C) << 8) | ((BLTag)(D))))

//! \}

//! \cond INTERNAL
//! \name Internals
//! \{

//! \def BL_DEFINE_ENUM(NAME)
//!
//! Defines an enumeration used by Blend2D that is `uint32_t`.

//! \def BL_FORCE_ENUM_UINT32(ENUM_VALUE_PREFIX)
//!
//! Forces an enumeration to be represented as 32-bit unsigned integer.
//!
//! This must be used in public C API, because when compiled by a C compiler (not C++ compiler) the enums won't
//! have type information (it's a C++ feature). So this macro adds an additional enum value that would force the
//! C compiler to make the type unsigned and at 32-bit.

//! \}
//! \endcond

#ifdef __cplusplus
  #define BL_DEFINE_CONST static constexpr
  #define BL_DEFINE_ENUM(NAME) enum NAME : uint32_t
  #define BL_FORCE_ENUM_UINT32(ENUM_VALUE_PREFIX)
#else
  #define BL_DEFINE_CONST static const
  #define BL_DEFINE_ENUM(NAME) typedef enum NAME NAME; enum NAME
  #define BL_FORCE_ENUM_UINT32(ENUM_VALUE_PREFIX) ,ENUM_VALUE_PREFIX##_FORCE_UINT = 0xFFFFFFFFu
#endif

//! \cond INTERNAL
//! \name Internals
//! \{

//! \def BL_BEGIN_C_DECLS
//! Begins C declarations scope when compiling with a C++ compiler.

//! \def BL_END_C_DECLS
//! Ends C declarations scope when compiling with a C++ compiler.

//! \}
//! \endcond

#ifdef __cplusplus
  #define BL_BEGIN_C_DECLS extern "C" {
  #define BL_END_C_DECLS } /* {ExternC} */
#else
  #define BL_BEGIN_C_DECLS
  #define BL_END_C_DECLS
#endif

//! \cond INTERNAL
//! \name Compiler Diagnostics
//! \{

// Diagnostic warnings can be turned on/off by using pragmas, however, this is a compiler specific stuff we have to
// maintain for each compiler. Ideally we should have a clean code that would compiler without any warnings with all
// of them enabled by default, but since there is a lot of nitpicks we just disable some locally when needed (like
// unused parameter in null-impl functions, etc).
#if defined(__clang__)
  #define BL_DIAGNOSTIC_PUSH(...)              _Pragma("clang diagnostic push") __VA_ARGS__
  #define BL_DIAGNOSTIC_POP                    _Pragma("clang diagnostic pop")
  #define BL_DIAGNOSTIC_NO_UNUSED_PARAMETERS   _Pragma("clang diagnostic ignored \"-Wunused-parameter\"")
  #define BL_DIAGNOSTIC_NO_EXTRA_WARNINGS      _Pragma("clang diagnostic ignored \"-Wextra\"")
#elif defined(__GNUC__)
  #define BL_DIAGNOSTIC_PUSH(...)              _Pragma("GCC diagnostic push") __VA_ARGS__
  #define BL_DIAGNOSTIC_POP                    _Pragma("GCC diagnostic pop")
  #define BL_DIAGNOSTIC_NO_UNUSED_PARAMETERS   _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")
  #define BL_DIAGNOSTIC_NO_EXTRA_WARNINGS      _Pragma("GCC diagnostic ignored \"-Wextra\"")
#elif defined(_MSC_VER)
  #define BL_DIAGNOSTIC_PUSH(...)              __pragma(warning(push)) __VA_ARGS__
  #define BL_DIAGNOSTIC_POP                    __pragma(warning(pop))
  #define BL_DIAGNOSTIC_NO_UNUSED_PARAMETERS   __pragma(warning(disable: 4100))
  #define BL_DIAGNOSTIC_NO_EXTRA_WARNINGS
#endif

#if !defined(BL_DIAGNOSTIC_PUSH)
  #define BL_DIAGNOSTIC_PUSH(...)
  #define BL_DIAGNOSTIC_POP
  #define BL_DIAGNOSTIC_NO_UNUSED_PARAMETERS
  #define BL_DIAGNOSTIC_NO_EXTRA_WARNINGS
#endif

//! \}
//! \endcond

//! \}

// Forward Declarations
// ====================

#ifdef __cplusplus
  #define BL_FORWARD_DECLARE_STRUCT(NAME) struct NAME
#else
  #define BL_FORWARD_DECLARE_STRUCT(NAME) typedef struct NAME NAME
#endif

#ifdef __cplusplus
  #define BL_FORWARD_DECLARE_UNION(NAME) union NAME
#else
  #define BL_FORWARD_DECLARE_UNION(NAME) typedef union NAME NAME
#endif

#ifdef __cplusplus
  #define BL_FORWARD_DECLARE_ENUM(NAME) enum NAME : uint32_t
#else
  #define BL_FORWARD_DECLARE_ENUM(NAME) typedef enum NAME NAME
#endif

BL_FORWARD_DECLARE_STRUCT(BLRange);
BL_FORWARD_DECLARE_STRUCT(BLRandom);
BL_FORWARD_DECLARE_STRUCT(BLFileCore);
BL_FORWARD_DECLARE_STRUCT(BLFileInfo);

BL_FORWARD_DECLARE_STRUCT(BLRuntimeScopeCore);
BL_FORWARD_DECLARE_STRUCT(BLRuntimeBuildInfo);
BL_FORWARD_DECLARE_STRUCT(BLRuntimeSystemInfo);
BL_FORWARD_DECLARE_STRUCT(BLRuntimeResourceInfo);

BL_FORWARD_DECLARE_STRUCT(BLRgba);
BL_FORWARD_DECLARE_STRUCT(BLRgba32);
BL_FORWARD_DECLARE_STRUCT(BLRgba64);

BL_FORWARD_DECLARE_STRUCT(BLPoint);
BL_FORWARD_DECLARE_STRUCT(BLPointI);
BL_FORWARD_DECLARE_STRUCT(BLSize);
BL_FORWARD_DECLARE_STRUCT(BLSizeI);
BL_FORWARD_DECLARE_STRUCT(BLBox);
BL_FORWARD_DECLARE_STRUCT(BLBoxI);
BL_FORWARD_DECLARE_STRUCT(BLRect);
BL_FORWARD_DECLARE_STRUCT(BLRectI);
BL_FORWARD_DECLARE_STRUCT(BLLine);
BL_FORWARD_DECLARE_STRUCT(BLTriangle);
BL_FORWARD_DECLARE_STRUCT(BLRoundRect);
BL_FORWARD_DECLARE_STRUCT(BLCircle);
BL_FORWARD_DECLARE_STRUCT(BLEllipse);
BL_FORWARD_DECLARE_STRUCT(BLArc);

BL_FORWARD_DECLARE_STRUCT(BLMatrix2D);
BL_FORWARD_DECLARE_STRUCT(BLApproximationOptions);
BL_FORWARD_DECLARE_STRUCT(BLStrokeOptionsCore);

BL_FORWARD_DECLARE_STRUCT(BLFormatInfo);

BL_FORWARD_DECLARE_STRUCT(BLObjectCore);
BL_FORWARD_DECLARE_STRUCT(BLObjectImpl);
BL_FORWARD_DECLARE_STRUCT(BLObjectVirt);
BL_FORWARD_DECLARE_STRUCT(BLObjectVirtBase);
BL_FORWARD_DECLARE_STRUCT(BLObjectInfo);
BL_FORWARD_DECLARE_UNION(BLObjectDetail);

BL_FORWARD_DECLARE_STRUCT(BLArrayCore);
BL_FORWARD_DECLARE_STRUCT(BLArrayImpl);

BL_FORWARD_DECLARE_STRUCT(BLBitArrayCore);
BL_FORWARD_DECLARE_STRUCT(BLBitArrayImpl);

BL_FORWARD_DECLARE_STRUCT(BLBitSetCore);
BL_FORWARD_DECLARE_STRUCT(BLBitSetData);
BL_FORWARD_DECLARE_STRUCT(BLBitSetImpl);
BL_FORWARD_DECLARE_STRUCT(BLBitSetSegment);
BL_FORWARD_DECLARE_STRUCT(BLBitSetBuilderCore);

BL_FORWARD_DECLARE_STRUCT(BLStringCore);
BL_FORWARD_DECLARE_STRUCT(BLStringImpl);

BL_FORWARD_DECLARE_STRUCT(BLPathCore);
BL_FORWARD_DECLARE_STRUCT(BLPathImpl);
BL_FORWARD_DECLARE_STRUCT(BLPathView);

BL_FORWARD_DECLARE_STRUCT(BLImageData);
BL_FORWARD_DECLARE_STRUCT(BLImageInfo);

BL_FORWARD_DECLARE_STRUCT(BLImageCore);
BL_FORWARD_DECLARE_STRUCT(BLImageImpl);

BL_FORWARD_DECLARE_STRUCT(BLImageCodecCore);
BL_FORWARD_DECLARE_STRUCT(BLImageCodecImpl);
BL_FORWARD_DECLARE_STRUCT(BLImageCodecVirt);

BL_FORWARD_DECLARE_STRUCT(BLImageDecoderCore);
BL_FORWARD_DECLARE_STRUCT(BLImageDecoderImpl);
BL_FORWARD_DECLARE_STRUCT(BLImageDecoderVirt);

BL_FORWARD_DECLARE_STRUCT(BLImageEncoderCore);
BL_FORWARD_DECLARE_STRUCT(BLImageEncoderImpl);
BL_FORWARD_DECLARE_STRUCT(BLImageEncoderVirt);

BL_FORWARD_DECLARE_STRUCT(BLPixelConverterCore);
BL_FORWARD_DECLARE_STRUCT(BLPixelConverterOptions);

BL_FORWARD_DECLARE_STRUCT(BLGradientCore);
BL_FORWARD_DECLARE_STRUCT(BLGradientImpl);
BL_FORWARD_DECLARE_STRUCT(BLGradientStop);

BL_FORWARD_DECLARE_STRUCT(BLLinearGradientValues);
BL_FORWARD_DECLARE_STRUCT(BLRadialGradientValues);
BL_FORWARD_DECLARE_STRUCT(BLConicGradientValues);

BL_FORWARD_DECLARE_STRUCT(BLPatternCore);
BL_FORWARD_DECLARE_STRUCT(BLPatternImpl);

BL_FORWARD_DECLARE_STRUCT(BLContextCookie);
BL_FORWARD_DECLARE_STRUCT(BLContextCreateInfo);
BL_FORWARD_DECLARE_STRUCT(BLContextHints);
BL_FORWARD_DECLARE_STRUCT(BLContextState);

BL_FORWARD_DECLARE_STRUCT(BLContextCore);
BL_FORWARD_DECLARE_STRUCT(BLContextImpl);
BL_FORWARD_DECLARE_STRUCT(BLContextVirt);

BL_FORWARD_DECLARE_STRUCT(BLGlyphBufferCore);
BL_FORWARD_DECLARE_STRUCT(BLGlyphBufferImpl);
BL_FORWARD_DECLARE_STRUCT(BLGlyphInfo);
BL_FORWARD_DECLARE_STRUCT(BLGlyphMappingState);
BL_FORWARD_DECLARE_STRUCT(BLGlyphOutlineSinkInfo);
BL_FORWARD_DECLARE_STRUCT(BLGlyphPlacement);
BL_FORWARD_DECLARE_STRUCT(BLGlyphRun);

BL_FORWARD_DECLARE_STRUCT(BLFontCoverageInfo);
BL_FORWARD_DECLARE_STRUCT(BLFontFaceInfo);
BL_FORWARD_DECLARE_STRUCT(BLFontQueryProperties);
BL_FORWARD_DECLARE_STRUCT(BLFontFeatureItem);
BL_FORWARD_DECLARE_STRUCT(BLFontFeatureSettingsCore);
BL_FORWARD_DECLARE_STRUCT(BLFontFeatureSettingsImpl);
BL_FORWARD_DECLARE_STRUCT(BLFontFeatureSettingsView);
BL_FORWARD_DECLARE_STRUCT(BLFontDesignMetrics);
BL_FORWARD_DECLARE_STRUCT(BLFontMatrix);
BL_FORWARD_DECLARE_STRUCT(BLFontMetrics);
BL_FORWARD_DECLARE_STRUCT(BLFontPanoseInfo);
BL_FORWARD_DECLARE_STRUCT(BLFontTable);
BL_FORWARD_DECLARE_STRUCT(BLFontVariationItem);
BL_FORWARD_DECLARE_STRUCT(BLFontVariationSettingsCore);
BL_FORWARD_DECLARE_STRUCT(BLFontVariationSettingsImpl);
BL_FORWARD_DECLARE_STRUCT(BLFontVariationSettingsView);
BL_FORWARD_DECLARE_STRUCT(BLTextMetrics);

BL_FORWARD_DECLARE_STRUCT(BLFontCore);
BL_FORWARD_DECLARE_STRUCT(BLFontImpl);

BL_FORWARD_DECLARE_STRUCT(BLFontDataCore);
BL_FORWARD_DECLARE_STRUCT(BLFontDataImpl);
BL_FORWARD_DECLARE_STRUCT(BLFontDataVirt);

BL_FORWARD_DECLARE_STRUCT(BLFontFaceCore);
BL_FORWARD_DECLARE_STRUCT(BLFontFaceImpl);
BL_FORWARD_DECLARE_STRUCT(BLFontFaceVirt);

BL_FORWARD_DECLARE_STRUCT(BLFontManagerCore);
BL_FORWARD_DECLARE_STRUCT(BLFontManagerImpl);
BL_FORWARD_DECLARE_STRUCT(BLFontManagerVirt);

BL_FORWARD_DECLARE_STRUCT(BLVarCore);

#undef BL_FORWARD_DECLARE_ENUM
#undef BL_FORWARD_DECLARE_UNION
#undef BL_FORWARD_DECLARE_STRUCT

// C++ API.
#ifdef __cplusplus
class BLFile;
class BLRuntimeScope;
template<typename T> class BLArray;
class BLBitArray;
class BLBitSet;
template<uint32_t> class BLBitSetBuilderT;
class BLString;
class BLPath;
class BLStrokeOptions;
class BLImage;
class BLImageCodec;
class BLImageDecoder;
class BLImageEncoder;
class BLPattern;
class BLGradient;
class BLContext;
class BLPixelConverter;
class BLGlyphBuffer;
class BLGlyphRunIterator;
class BLFont;
class BLFontData;
class BLFontFace;
class BLFontFeatureSettings;
class BLFontManager;
class BLFontVariationSettings;
class BLVar;
#endif

// Public Types
// ============

//! \ingroup bl_globals
//!
//! Result code used by most Blend2D functions (32-bit unsigned integer).
//!
//! The \ref BLResultCode enumeration contains Blend2D result codes that contain Blend2D specific set of errors
//! and an extended set of errors that can come from WIN32 or POSIX APIs. Since the success result code is zero
//! it's recommended to use the following check to determine whether a call failed or not:
//!
//! ```
//! BLResult result = do_something();
//! if (result != BL_SUCCESS) {
//!   // `do_something()` failed...
//! }
//! ```
typedef uint32_t BLResult;

//! \ingroup bl_globals
//!
//! Tag is a 32-bit integer consisting of 4 characters in the following format:
//!
//! ```
//! tag = ((a << 24) | (b << 16) | (c << 8) | d)
//! ```
//!
//! Tags are used extensively by OpenType fonts and other binary formats like PNG. In most cases TAGs should only
//! contain ASCII letters, digits, and spaces.
//!
//! Blend2D uses \ref BLTag in public and internal APIs to distinguish between a regular `uint32_t` and tag.
typedef uint32_t BLTag;

//! \ingroup bl_globals
//!
//! Unique identifier that can be used for caching purposes.
//!
//! Some objects such as \ref BLImage and \ref BLFontFace have assigned an unique identifier that can be used to
//! identify such objects for caching purposes. This identifier is never zero, so zero can be safely used as
//! "uncached".
//!
//! \note Unique identifier is per-process. It's implemented as an increasing global or thread-local counter in
//! a way that identifiers would not collide.
typedef uint64_t BLUniqueId;

//! \ingroup bl_globals
//!
//! BLUnknown is `void` - it's used in places that accept pointer to \ref BLVarCore or any \ref BLObjectCore
//! compatible object.
typedef void BLUnknown;

//! \ingroup bl_globals
//!
//! A sink that can be used to debug various parts of Blend2D.
typedef void (BL_CDECL* BLDebugMessageSinkFunc)(const char* message, size_t size, void* user_data) BL_NOEXCEPT_C;

// Public Constants
// ================

//! \ingroup bl_globals
//!
//! Blend2D result code.
BL_DEFINE_ENUM(BLResultCode) {
  //! Successful result code.
  BL_SUCCESS = 0,

  BL_ERROR_START_INDEX = 0x00010000u,

  BL_ERROR_OUT_OF_MEMORY = 0x00010000u,  //!< Out of memory                 [ENOMEM].
  BL_ERROR_INVALID_VALUE,                //!< Invalid value/argument        [EINVAL].
  BL_ERROR_INVALID_STATE,                //!< Invalid state                 [EFAULT].
  BL_ERROR_INVALID_HANDLE,               //!< Invalid handle or file.       [EBADF].
  BL_ERROR_INVALID_CONVERSION,           //!< Invalid conversion.
  BL_ERROR_OVERFLOW,                     //!< Overflow or value too large   [EOVERFLOW].
  BL_ERROR_NOT_INITIALIZED,              //!< Object not initialized.
  BL_ERROR_NOT_IMPLEMENTED,              //!< Not implemented               [ENOSYS].
  BL_ERROR_NOT_PERMITTED,                //!< Operation not permitted       [EPERM].

  BL_ERROR_IO,                           //!< IO error                      [EIO].
  BL_ERROR_BUSY,                         //!< Device or resource busy       [EBUSY].
  BL_ERROR_INTERRUPTED,                  //!< Operation interrupted         [EINTR].
  BL_ERROR_TRY_AGAIN,                    //!< Try again                     [EAGAIN].
  BL_ERROR_TIMED_OUT,                    //!< Timed out                     [ETIMEDOUT].
  BL_ERROR_BROKEN_PIPE,                  //!< Broken pipe                   [EPIPE].
  BL_ERROR_INVALID_SEEK,                 //!< File is not seekable          [ESPIPE].
  BL_ERROR_SYMLINK_LOOP,                 //!< Too many levels of symlinks   [ELOOP].
  BL_ERROR_FILE_TOO_LARGE,               //!< File is too large             [EFBIG].
  BL_ERROR_ALREADY_EXISTS,               //!< File/directory already exists [EEXIST].
  BL_ERROR_ACCESS_DENIED,                //!< Access denied                 [EACCES].
  BL_ERROR_MEDIA_CHANGED,                //!< Media changed                 [Windows::ERROR_MEDIA_CHANGED].
  BL_ERROR_READ_ONLY_FS,                 //!< The file/FS is read-only      [EROFS].
  BL_ERROR_NO_DEVICE,                    //!< Device doesn't exist          [ENXIO].
  BL_ERROR_NO_ENTRY,                     //!< Not found, no entry (fs)      [ENOENT].
  BL_ERROR_NO_MEDIA,                     //!< No media in drive/device      [ENOMEDIUM].
  BL_ERROR_NO_MORE_DATA,                 //!< No more data / end of file    [ENODATA].
  BL_ERROR_NO_MORE_FILES,                //!< No more files                 [ENMFILE].
  BL_ERROR_NO_SPACE_LEFT,                //!< No space left on device       [ENOSPC].
  BL_ERROR_NOT_EMPTY,                    //!< Directory is not empty        [ENOTEMPTY].
  BL_ERROR_NOT_FILE,                     //!< Not a file                    [EISDIR].
  BL_ERROR_NOT_DIRECTORY,                //!< Not a directory               [ENOTDIR].
  BL_ERROR_NOT_SAME_DEVICE,              //!< Not same device               [EXDEV].
  BL_ERROR_NOT_BLOCK_DEVICE,             //!< Not a block device            [ENOTBLK].

  BL_ERROR_INVALID_FILE_NAME,            //!< File/path name is invalid     [n/a].
  BL_ERROR_FILE_NAME_TOO_LONG,           //!< File/path name is too long    [ENAMETOOLONG].

  BL_ERROR_TOO_MANY_OPEN_FILES,          //!< Too many open files           [EMFILE].
  BL_ERROR_TOO_MANY_OPEN_FILES_BY_OS,    //!< Too many open files by OS     [ENFILE].
  BL_ERROR_TOO_MANY_LINKS,               //!< Too many symbolic links on FS [EMLINK].
  BL_ERROR_TOO_MANY_THREADS,             //!< Too many threads              [EAGAIN].
  BL_ERROR_THREAD_POOL_EXHAUSTED,        //!< Thread pool is exhausted and couldn't acquire the requested thread count.

  BL_ERROR_FILE_EMPTY,                   //!< File is empty (not specific to any OS error).
  BL_ERROR_OPEN_FAILED,                  //!< File open failed              [Windows::ERROR_OPEN_FAILED].
  BL_ERROR_NOT_ROOT_DEVICE,              //!< Not a root device/directory   [Windows::ERROR_DIR_NOT_ROOT].

  BL_ERROR_UNKNOWN_SYSTEM_ERROR,         //!< Unknown system error that failed to translate to Blend2D result code.

  BL_ERROR_INVALID_ALIGNMENT,            //!< Invalid data alignment.
  BL_ERROR_INVALID_SIGNATURE,            //!< Invalid data signature or header.
  BL_ERROR_INVALID_DATA,                 //!< Invalid or corrupted data.
  BL_ERROR_INVALID_STRING,               //!< Invalid string (invalid data of either UTF8, UTF16, or UTF32).
  BL_ERROR_INVALID_KEY,                  //!< Invalid key or property.
  BL_ERROR_DATA_TRUNCATED,               //!< Truncated data (more data required than memory/stream provides).
  BL_ERROR_DATA_TOO_LARGE,               //!< Input data too large to be processed.
  BL_ERROR_DECOMPRESSION_FAILED,         //!< Decompression failed due to invalid data (RLE, Huffman, etc).

  BL_ERROR_INVALID_GEOMETRY,             //!< Invalid geometry (invalid path data or shape).
  BL_ERROR_NO_MATCHING_VERTEX,           //!< Returned when there is no matching vertex in path data.

  BL_ERROR_INVALID_CREATE_FLAGS,         //!< Invalid create flags (BLContext).
  BL_ERROR_NO_MATCHING_COOKIE,           //!< No matching cookie (BLContext).
  BL_ERROR_NO_STATES_TO_RESTORE,         //!< No states to restore (BLContext).
  BL_ERROR_TOO_MANY_SAVED_STATES,        //!< Cannot save state as the number of saved states reached the limit (BLContext).

  BL_ERROR_IMAGE_TOO_LARGE,              //!< The size of the image is too large.
  BL_ERROR_IMAGE_NO_MATCHING_CODEC,      //!< Image codec for a required format doesn't exist.
  BL_ERROR_IMAGE_UNKNOWN_FILE_FORMAT,    //!< Unknown or invalid file format that cannot be read.
  BL_ERROR_IMAGE_DECODER_NOT_PROVIDED,   //!< Image codec doesn't support reading the file format.
  BL_ERROR_IMAGE_ENCODER_NOT_PROVIDED,   //!< Image codec doesn't support writing the file format.

  BL_ERROR_PNG_MULTIPLE_IHDR,            //!< Multiple IHDR chunks are not allowed (PNG).
  BL_ERROR_PNG_INVALID_IDAT,             //!< Invalid IDAT chunk (PNG).
  BL_ERROR_PNG_INVALID_IEND,             //!< Invalid IEND chunk (PNG).
  BL_ERROR_PNG_INVALID_PLTE,             //!< Invalid PLTE chunk (PNG).
  BL_ERROR_PNG_INVALID_TRNS,             //!< Invalid tRNS chunk (PNG).
  BL_ERROR_PNG_INVALID_FILTER,           //!< Invalid filter type (PNG).

  BL_ERROR_JPEG_UNSUPPORTED_FEATURE,     //!< Unsupported feature (JPEG).
  BL_ERROR_JPEG_INVALID_SOS,             //!< Invalid SOS marker or header (JPEG).
  BL_ERROR_JPEG_INVALID_SOF,             //!< Invalid SOF marker (JPEG).
  BL_ERROR_JPEG_MULTIPLE_SOF,            //!< Multiple SOF markers (JPEG).
  BL_ERROR_JPEG_UNSUPPORTED_SOF,         //!< Unsupported SOF marker (JPEG).

  BL_ERROR_FONT_NOT_INITIALIZED,         //!< Font doesn't have any data as it's not initialized.
  BL_ERROR_FONT_NO_MATCH,                //!< Font or font face was not matched (BLFontManager).
  BL_ERROR_FONT_NO_CHARACTER_MAPPING,    //!< Font has no character to glyph mapping data.
  BL_ERROR_FONT_MISSING_IMPORTANT_TABLE, //!< Font has missing an important table.
  BL_ERROR_FONT_FEATURE_NOT_AVAILABLE,   //!< Font feature is not available.
  BL_ERROR_FONT_CFF_INVALID_DATA,        //!< Font has an invalid CFF data.
  BL_ERROR_FONT_PROGRAM_TERMINATED,      //!< Font program terminated because the execution reached the limit.
  BL_ERROR_GLYPH_SUBSTITUTION_TOO_LARGE, //!< Glyph substitution requires too much space and was terminated.

  BL_ERROR_INVALID_GLYPH                 //!< Invalid glyph identifier.

  BL_FORCE_ENUM_UINT32(BL_ERROR)
};

//! \ingroup bl_globals
//!
//! Byte order.
BL_DEFINE_ENUM(BLByteOrder) {
  //! Little endian byte-order.
  BL_BYTE_ORDER_LE = 0,
  //! Big endian byte-order.
  BL_BYTE_ORDER_BE = 1,

  //! Native (host) byte-order.
  BL_BYTE_ORDER_NATIVE = BL_BYTE_ORDER == 1234 ? BL_BYTE_ORDER_LE : BL_BYTE_ORDER_BE,
  //! Swapped byte-order (BE if host is LE and vice versa).
  BL_BYTE_ORDER_SWAPPED = BL_BYTE_ORDER == 1234 ? BL_BYTE_ORDER_BE : BL_BYTE_ORDER_LE

  BL_FORCE_ENUM_UINT32(BL_BYTE_ORDER)
};

//! \ingroup bl_globals
//!
//! Data access flags.
BL_DEFINE_ENUM(BLDataAccessFlags) {
  //! No data access flags.
  BL_DATA_ACCESS_NO_FLAGS = 0x00u,
  //! Read access.
  BL_DATA_ACCESS_READ = 0x01u,
  //! Write access.
  BL_DATA_ACCESS_WRITE = 0x02u,
  //! Read and write access.
  BL_DATA_ACCESS_RW = 0x03u

  BL_FORCE_ENUM_UINT32(BL_DATA_ACCESS)
};

//! \ingroup bl_globals
//!
//! Data source type.
BL_DEFINE_ENUM(BLDataSourceType) {
  //! No data source.
  BL_DATA_SOURCE_TYPE_NONE = 0,
  //! Memory data source.
  BL_DATA_SOURCE_TYPE_MEMORY = 1,
  //! File data source.
  BL_DATA_SOURCE_TYPE_FILE = 2,
  //! Custom data source.
  BL_DATA_SOURCE_TYPE_CUSTOM = 3,

  //! Maximum value `BLDataSourceType`.
  BL_DATA_SOURCE_TYPE_MAX_VALUE = 3

  BL_FORCE_ENUM_UINT32(BL_DATA_SOURCE_TYPE)
};

//! \ingroup bl_globals
//!
//! Modification operation applied to Blend2D containers.
BL_DEFINE_ENUM(BLModifyOp) {
  //! Assign operation, which reserves space only to fit the requested input.
  BL_MODIFY_OP_ASSIGN_FIT = 0,
  //! Assign operation, which takes into consideration successive appends.
  BL_MODIFY_OP_ASSIGN_GROW = 1,
  //! Append operation, which reserves space only to fit the current and appended content.
  BL_MODIFY_OP_APPEND_FIT = 2,
  //! Append operation, which takes into consideration successive appends.
  BL_MODIFY_OP_APPEND_GROW = 3,

  //! Maximum value of `BLModifyOp`.
  BL_MODIFY_OP_MAX_VALUE = 3

  BL_FORCE_ENUM_UINT32(BL_MODIFY_OP)
};

//! \ingroup bl_globals
//!
//! Boolean operator.
BL_DEFINE_ENUM(BLBooleanOp) {
  //! Result = B.
  BL_BOOLEAN_OP_COPY = 0,
  //! Result = A & B.
  BL_BOOLEAN_OP_AND = 1,
  //! Result = A | B.
  BL_BOOLEAN_OP_OR = 2,
  //! Result = A ^ B.
  BL_BOOLEAN_OP_XOR = 3,
  //! Result = A & ~B.
  BL_BOOLEAN_OP_AND_NOT = 4,
  //! Result = ~A & B.
  BL_BOOLEAN_OP_NOT_AND = 5,

  //! Maximum value of `BLBooleanOp`.
  BL_BOOLEAN_OP_MAX_VALUE = 5

  BL_FORCE_ENUM_UINT32(BL_BOOLEAN_OP)
};

//! \ingroup bl_styling
//!
//! Extend mode.
BL_DEFINE_ENUM(BLExtendMode) {
  //! Pad extend [default].
  BL_EXTEND_MODE_PAD = 0,
  //! Repeat extend.
  BL_EXTEND_MODE_REPEAT = 1,
  //! Reflect extend.
  BL_EXTEND_MODE_REFLECT = 2,

  //! Alias of `BL_EXTEND_MODE_PAD`.
  BL_EXTEND_MODE_PAD_X_PAD_Y = 0,
  //! Pad X and repeat Y.
  BL_EXTEND_MODE_PAD_X_REPEAT_Y = 3,
  //! Pad X and reflect Y.
  BL_EXTEND_MODE_PAD_X_REFLECT_Y = 4,

  //! Alias of `BL_EXTEND_MODE_REPEAT`.
  BL_EXTEND_MODE_REPEAT_X_REPEAT_Y = 1,
  //! Repeat X and pad Y.
  BL_EXTEND_MODE_REPEAT_X_PAD_Y = 5,
  //! Repeat X and reflect Y.
  BL_EXTEND_MODE_REPEAT_X_REFLECT_Y = 6,

  //! Alias of `BL_EXTEND_MODE_REFLECT`.
  BL_EXTEND_MODE_REFLECT_X_REFLECT_Y = 2,
  //! Reflect X and pad Y.
  BL_EXTEND_MODE_REFLECT_X_PAD_Y = 7,
  //! Reflect X and repeat Y.
  BL_EXTEND_MODE_REFLECT_X_REPEAT_Y = 8,

  //! Count of simple extend modes (that use the same value for X and Y).
  BL_EXTEND_MODE_SIMPLE_MAX_VALUE = 2,
  //! Count of complex extend modes (that can use independent values for X and Y).
  BL_EXTEND_MODE_COMPLEX_MAX_VALUE = 8,

  //! Maximum value of `BLExtendMode`.
  BL_EXTEND_MODE_MAX_VALUE = 8

  BL_FORCE_ENUM_UINT32(BL_EXTEND_MODE)
};

//! \ingroup bl_text
//!
//! Text encoding.
BL_DEFINE_ENUM(BLTextEncoding) {
  //! UTF-8 encoding.
  BL_TEXT_ENCODING_UTF8 = 0,
  //! UTF-16 encoding (native endian).
  BL_TEXT_ENCODING_UTF16 = 1,
  //! UTF-32 encoding (native endian).
  BL_TEXT_ENCODING_UTF32 = 2,
  //! LATIN1 encoding (one byte per character).
  BL_TEXT_ENCODING_LATIN1 = 3,

  //! Platform native `wchar_t` (or Windows `WCHAR`) encoding, alias to
  //! either UTF-32, UTF-16, or UTF-8 depending on `sizeof(wchar_t)`.
  BL_TEXT_ENCODING_WCHAR
    = sizeof(wchar_t) == 4 ? BL_TEXT_ENCODING_UTF32 :
      sizeof(wchar_t) == 2 ? BL_TEXT_ENCODING_UTF16 : BL_TEXT_ENCODING_UTF8,

  //! Maximum value of `BLTextEncoding`.
  BL_TEXT_ENCODING_MAX_VALUE = 3

  BL_FORCE_ENUM_UINT32(BL_TEXT_ENCODING)
};

// Internal API
// ============

#ifdef __cplusplus
//! \cond INTERNAL

//! \ingroup blend2d_internal
//!
//! Internal namespace that should never be used by Blend2D users.
//!
//! This namespace provides functionality that is internally used by the public C++ API in public headers.
//! There should never be functionality that is not used by public headers, that should always be hidden.
namespace BLInternal {

template<typename T>
[[nodiscard]]
BL_INLINE_NODEBUG std::remove_reference_t<T>&& move(T&& v) noexcept { return static_cast<std::remove_reference_t<T>&&>(v); }

template<typename T>
[[nodiscard]]
BL_INLINE_NODEBUG T&& forward(std::remove_reference_t<T>& v) noexcept { return static_cast<T&&>(v); }

template<typename T>
[[nodiscard]]
BL_INLINE_NODEBUG T&& forward(std::remove_reference_t<T>&& v) noexcept { return static_cast<T&&>(v); }

template<typename T>
BL_INLINE void swap(T& t1, T& t2) noexcept {
  T temp(move(t1));
  t1 = move(t2);
  t2 = move(temp);
}

template<typename... Args>
[[nodiscard]]
BL_INLINE_CONSTEXPR bool bool_and(Args&&... args) noexcept { return bool( (... & unsigned(forward<Args>(args))) ); }

template<typename... Args>
[[nodiscard]]
BL_INLINE_CONSTEXPR bool bool_or(Args&&... args) noexcept { return bool( (... | unsigned(forward<Args>(args))) ); }

//! StdIntT provides a signed integer type as defined by <stdint.h> by size.
template<size_t kSize, bool kUnsigned = false> struct StdIntT;

template<> struct StdIntT<1, false> { using Type = int8_t; };
template<> struct StdIntT<2, false> { using Type = int16_t; };
template<> struct StdIntT<4, false> { using Type = int32_t; };
template<> struct StdIntT<8, false> { using Type = int64_t; };
template<> struct StdIntT<1, true> { using Type = uint8_t; };
template<> struct StdIntT<2, true> { using Type = uint16_t; };
template<> struct StdIntT<4, true> { using Type = uint32_t; };
template<> struct StdIntT<8, true> { using Type = uint64_t; };

template<size_t kSize, bool kUnsigned = false>
using IntBySize = typename StdIntT<kSize, kUnsigned>::Type;

template<size_t kSize>
using UIntBySize = typename StdIntT<kSize, true>::Type;

template<typename T, bool kUnsigned = false>
using IntByType = typename StdIntT<sizeof(T), kUnsigned>::Type;

template<typename T>
using UIntByType = typename StdIntT<sizeof(T), 1>::Type;

template<uint64_t kInput>
struct ConstCTZ {
  static inline constexpr uint32_t kValue =
    (kInput & (uint64_t(1) <<  0)) ?  0 : (kInput & (uint64_t(1) <<  1)) ?  1 :
    (kInput & (uint64_t(1) <<  2)) ?  2 : (kInput & (uint64_t(1) <<  3)) ?  3 :
    (kInput & (uint64_t(1) <<  4)) ?  4 : (kInput & (uint64_t(1) <<  5)) ?  5 :
    (kInput & (uint64_t(1) <<  6)) ?  6 : (kInput & (uint64_t(1) <<  7)) ?  7 :
    (kInput & (uint64_t(1) <<  8)) ?  8 : (kInput & (uint64_t(1) <<  9)) ?  9 :
    (kInput & (uint64_t(1) << 10)) ? 10 : (kInput & (uint64_t(1) << 11)) ? 11 :
    (kInput & (uint64_t(1) << 12)) ? 12 : (kInput & (uint64_t(1) << 13)) ? 13 :
    (kInput & (uint64_t(1) << 14)) ? 14 : (kInput & (uint64_t(1) << 15)) ? 15 :
    (kInput & (uint64_t(1) << 16)) ? 16 : (kInput & (uint64_t(1) << 17)) ? 17 :
    (kInput & (uint64_t(1) << 18)) ? 18 : (kInput & (uint64_t(1) << 19)) ? 19 :
    (kInput & (uint64_t(1) << 20)) ? 20 : (kInput & (uint64_t(1) << 21)) ? 21 :
    (kInput & (uint64_t(1) << 22)) ? 22 : (kInput & (uint64_t(1) << 23)) ? 23 :
    (kInput & (uint64_t(1) << 24)) ? 24 : (kInput & (uint64_t(1) << 25)) ? 25 :
    (kInput & (uint64_t(1) << 26)) ? 26 : (kInput & (uint64_t(1) << 27)) ? 27 :
    (kInput & (uint64_t(1) << 28)) ? 28 : (kInput & (uint64_t(1) << 29)) ? 29 :
    (kInput & (uint64_t(1) << 30)) ? 30 : (kInput & (uint64_t(1) << 31)) ? 31 :
    (kInput & (uint64_t(1) << 32)) ? 32 : (kInput & (uint64_t(1) << 33)) ? 33 :
    (kInput & (uint64_t(1) << 34)) ? 34 : (kInput & (uint64_t(1) << 35)) ? 35 :
    (kInput & (uint64_t(1) << 36)) ? 36 : (kInput & (uint64_t(1) << 37)) ? 37 :
    (kInput & (uint64_t(1) << 38)) ? 38 : (kInput & (uint64_t(1) << 39)) ? 39 :
    (kInput & (uint64_t(1) << 40)) ? 40 : (kInput & (uint64_t(1) << 41)) ? 41 :
    (kInput & (uint64_t(1) << 42)) ? 42 : (kInput & (uint64_t(1) << 43)) ? 43 :
    (kInput & (uint64_t(1) << 44)) ? 44 : (kInput & (uint64_t(1) << 45)) ? 45 :
    (kInput & (uint64_t(1) << 46)) ? 46 : (kInput & (uint64_t(1) << 47)) ? 47 :
    (kInput & (uint64_t(1) << 48)) ? 48 : (kInput & (uint64_t(1) << 49)) ? 49 :
    (kInput & (uint64_t(1) << 50)) ? 50 : (kInput & (uint64_t(1) << 51)) ? 51 :
    (kInput & (uint64_t(1) << 52)) ? 52 : (kInput & (uint64_t(1) << 53)) ? 53 :
    (kInput & (uint64_t(1) << 54)) ? 54 : (kInput & (uint64_t(1) << 55)) ? 55 :
    (kInput & (uint64_t(1) << 56)) ? 56 : (kInput & (uint64_t(1) << 57)) ? 57 :
    (kInput & (uint64_t(1) << 58)) ? 58 : (kInput & (uint64_t(1) << 59)) ? 59 :
    (kInput & (uint64_t(1) << 60)) ? 60 : (kInput & (uint64_t(1) << 61)) ? 61 :
    (kInput & (uint64_t(1) << 62)) ? 62 : (kInput & (uint64_t(1) << 63)) ? 63 : 64;
};

//! Type category.
//!
//! Provides type categorization for compile-time type reflection that can be used by templates.
enum TypeCategory : uint32_t {
  //! Type is unknown.
  kTypeCategoryUnknown = 0,
  //! Type is a boolean (`bool`).
  kTypeCategoryBool = 1,
  //! Type is integral.
  kTypeCategoryInt = 2,
  //! Type is a floating point.
  kTypeCategoryFloat = 3,
  //! Type is a pointer.
  kTypeCategoryPtr = 4,
  //! Type is a structure.
  kTypeCategoryStruct = 5,
  //! Type is BLObject compatible.
  kTypeCategoryObject = 6
};

//! Type flags.
//!
//! Provides details about a categorized type.
enum TypeFlags : uint32_t {
  //! Type has no flags.
  kTypeNoFlags = 0x0000u,
  //! Type is primitive (either bool, integer, or floating point).
  kTypeFlagPrimitive = 0x0001u,
  //! Type is `BLArrayCore` or `BLArray<T>`.
  kTypeFlagArray = 0x0002u,
  //! Type is `BLVarCore` or `BLVar`
  kTypeFlagVar = 0x0004u,
  //! Type is `BLxxxCore` - C API type.
  kTypeFlagCore = 0x0008u,

  //! Type is `BLRgba`.
  kTypeFlagRgba = 0x0010u,
  //! Type is `BLRgba32`.
  kTypeFlagRgba32 = 0x0020u,
  //! Type is `BLRgba64`.
  kTypeFlagRgba64 = 0x0040u,
  //! Type is `BLGradient[Core]` or `BLPattern[Core]`.
  kTypeFlagStyle = 0x0080u
};

template<typename T>
struct TypeTraits {
  static inline constexpr uint32_t kCategory =
    std::is_pointer_v<T> ? kTypeCategoryPtr :
    std::is_integral_v<T> ? kTypeCategoryInt :
    std::is_floating_point_v<T> ? kTypeCategoryFloat : kTypeCategoryStruct;

  static inline constexpr uint32_t kFlags =
    std::is_pointer_v<T> ? kTypeFlagPrimitive :
    std::is_integral_v<T> ? kTypeFlagPrimitive :
    std::is_floating_point_v<T> ? kTypeFlagPrimitive : kTypeNoFlags;
};

template<>
struct TypeTraits<bool> {
  static inline constexpr uint32_t kCategory = kTypeCategoryBool;
  static inline constexpr uint32_t kFlags = kTypeFlagPrimitive;
};

// BLArrayCore and BLArray<T> specialization.
template<>
struct TypeTraits<BLArrayCore> {
  static inline constexpr uint32_t kCategory = kTypeCategoryObject;
  static inline constexpr uint32_t kFlags = kTypeFlagArray | kTypeFlagCore;
};

template<typename T>
struct TypeTraits<BLArray<T>> {
  static inline constexpr uint32_t kCategory = kTypeCategoryObject;
  static inline constexpr uint32_t kFlags = kTypeFlagArray;
};

// Other types compatible with BLObjectCore.
#define BL_DEFINE_OBJECT_TRAITS(T, Flags)                             \
  template<>                                                          \
  struct TypeTraits<T##Core> {                                        \
    static inline constexpr uint32_t kCategory = kTypeCategoryObject; \
    static inline constexpr uint32_t kFlags = Flags | kTypeFlagCore;  \
  };                                                                  \
                                                                      \
  template<>                                                          \
  struct TypeTraits<T> {                                              \
    static inline constexpr uint32_t kCategory = kTypeCategoryObject; \
    static inline constexpr uint32_t kFlags = Flags;                  \
  };

BL_DEFINE_OBJECT_TRAITS(BLBitArray             , kTypeNoFlags)
BL_DEFINE_OBJECT_TRAITS(BLBitSet               , kTypeNoFlags)
BL_DEFINE_OBJECT_TRAITS(BLContext              , kTypeNoFlags)
BL_DEFINE_OBJECT_TRAITS(BLFont                 , kTypeNoFlags)
BL_DEFINE_OBJECT_TRAITS(BLFontData             , kTypeNoFlags)
BL_DEFINE_OBJECT_TRAITS(BLFontFace             , kTypeNoFlags)
BL_DEFINE_OBJECT_TRAITS(BLFontFeatureSettings  , kTypeNoFlags)
BL_DEFINE_OBJECT_TRAITS(BLFontManager          , kTypeNoFlags)
BL_DEFINE_OBJECT_TRAITS(BLFontVariationSettings, kTypeNoFlags)
BL_DEFINE_OBJECT_TRAITS(BLGradient             , kTypeFlagStyle)
BL_DEFINE_OBJECT_TRAITS(BLImage                , kTypeNoFlags)
BL_DEFINE_OBJECT_TRAITS(BLImageCodec           , kTypeNoFlags)
BL_DEFINE_OBJECT_TRAITS(BLImageDecoder         , kTypeNoFlags)
BL_DEFINE_OBJECT_TRAITS(BLImageEncoder         , kTypeNoFlags)
BL_DEFINE_OBJECT_TRAITS(BLPath                 , kTypeNoFlags)
BL_DEFINE_OBJECT_TRAITS(BLPattern              , kTypeFlagStyle)
BL_DEFINE_OBJECT_TRAITS(BLString               , kTypeNoFlags)
BL_DEFINE_OBJECT_TRAITS(BLVar                  , kTypeFlagVar)

#undef BL_DEFINE_OBJECT_TRAITS

//! Helper to implement placement new/delete without relying on `<new>` header.
struct PlacementNew { void* ptr; };

} // {BLInternal}

//! Implementation of a placement new so we don't have to depend on `<new>`.
BL_INLINE_NODEBUG void* operator new(size_t, const BLInternal::PlacementNew& p) {
#if defined(_MSC_VER) && !defined(__clang__)
  BL_ASSUME(p.ptr != nullptr); // Otherwise MSVC would emit a nullptr check.
#endif
  return p.ptr;
}

BL_INLINE_NODEBUG void operator delete(void*, const BLInternal::PlacementNew&) noexcept {}

//! \endcond
#endif

// Public API - TraceError
// =======================

//! \addtogroup bl_globals
//! \{

//! \name Debugging Functionality
//! \{

//! Returns the `result` passed.
//!
//! Provided for debugging purposes. Putting a breakpoint inside `bl_make_error()` can help with tracing an origin
//! of errors reported / returned by Blend2D as each error goes through this function.
//!
//! It's a zero-cost solution that doesn't affect release builds in any way.
#ifdef __cplusplus
[[nodiscard]]
#endif
static inline BLResult bl_make_error(BLResult result) BL_NOEXCEPT_C { return result; }

BL_BEGIN_C_DECLS

//! This function is called by Blend2D when an internal assertion failure happens.
//!
//! Failing an assertion means that there is either a bug in Blend2D or in user code that uses Blend2D and that the
//! state of the application is already corrupted and thus irrecoverable. Note that this would be a fatal error if
//! this function gets called in production.
BL_API BL_NORETURN void BL_CDECL bl_runtime_assertion_failure(const char* file, int line, const char* msg) BL_NOEXCEPT_C;

BL_END_C_DECLS

//! \}
//! \}

// Public API - Templates
// ======================

#ifdef __cplusplus
// These are the only global functions provided in C++ mode. They are needed by C++ API wrappers and can be used
// freely by Blend2D users as these templates have specializations for some geometry types. For example \ref bl_min()
// works with numbers as well as with \ref BLPoint.

//! \addtogroup bl_globals
//! \{

//! \name Explicit Construction & Destruction.
//!
//! These should be only necessary when extending Blend2D.
//!
//! \{

//! Constructs an instance in place (calls its constructor) with optional `args`.
template<typename T, typename... Args>
static BL_INLINE void bl_call_ctor(T& instance, Args&&... args) noexcept {
  // Only needed by MSVC as otherwise it could generate null-pointer check before calling the constructor. If the
  // assumption is used with GCC or Clang it would emit a "-Wtautological-undefined-compare" warning so we really
  // have to only enable this for compilers that don't have the necessary diagnostics to remove the nullptr check.
#if defined(_MSC_VER) && !defined(__clang__)
  BL_ASSUME(&instance != nullptr);
#endif

  new(BLInternal::PlacementNew{&instance}) T(BLInternal::forward<Args>(args)...);
}

//! Destroys an instance in place (calls its destructor).
template<typename T>
static BL_INLINE void bl_call_dtor(T& instance) noexcept {
  // Only needed by MSVC as otherwise it could generate null-pointer check before calling the destructor. If the
  // assumption is used with GCC or Clang it would emit a "-Wtautological-undefined-compare" warning so we really
  // have to only enable this for compilers that don't have the necessary diagnostics to remove the nullptr check.
#if defined(_MSC_VER) && !defined(__clang__)
  BL_ASSUME(&instance != nullptr);
#endif

  instance.~T();
}

//! \}

//! \name Global C++ Functions
//! \{

//! Bit-cast `x` of `In` type to the given `Out` type.
//!
//! Useful to bit-cast between integers and floating points. The size of `Out` and `In` must be the same otherwise the
//! compilation would fail. Bit casting is used by \ref bl_equals() to implement bit equality for floating point types.
template<typename Out, typename In>
[[nodiscard]]
static BL_INLINE_NODEBUG Out bl_bit_cast(const In& x) noexcept {
  static_assert(sizeof(Out) == sizeof(In),
                "The size of 'In' and 'Out' types must match");
  union { In in; Out out; } u = { x };
  return u.out;
}

//! Returns an absolute value of `a`.
template<typename T>
[[nodiscard]]
BL_INLINE_CONSTEXPR T bl_abs(const T& a) noexcept { return T(a < T(0) ? -a : a); }

//! Returns a minimum value of `a` and `b`.
template<typename T>
[[nodiscard]]
BL_INLINE_CONSTEXPR T bl_min(const T& a, const T& b) noexcept { return T(b < a ? b : a); }

//! Returns a maximum value of `a` and `b`.
template<typename T>
[[nodiscard]]
BL_INLINE_CONSTEXPR T bl_max(const T& a, const T& b) noexcept { return T(a < b ? b : a); }

//! Clamps `a` to a range defined as `[b, c]`.
template<typename T>
[[nodiscard]]
BL_INLINE_CONSTEXPR T bl_clamp(const T& a, const T& b, const T& c) noexcept { return bl_min(c, bl_max(b, a)); }

//! Returns a minimum value of all arguments passed.
template<typename T, typename... Args>
[[nodiscard]]
BL_INLINE_CONSTEXPR T bl_min(const T& a, const T& b, Args&&... args) noexcept { return bl_min(bl_min(a, b), BLInternal::forward<Args>(args)...); }

//! Returns a maximum value of all arguments passed.
template<typename T, typename... Args>
[[nodiscard]]
BL_INLINE_CONSTEXPR T bl_max(const T& a, const T& b, Args&&... args) noexcept { return bl_max(bl_max(a, b), BLInternal::forward<Args>(args)...); }

//! Returns `true` if `a` and `b` equals at binary level.
//!
//! For example `bl_equals(NaN, NaN) == true`.
template<typename T>
[[nodiscard]]
BL_INLINE_NODEBUG bool bl_equals(const T& a, const T& b) noexcept { return a == b; }

//! \cond NEVER
template<>
[[nodiscard]]
BL_INLINE_NODEBUG bool bl_equals(const float& a, const float& b) noexcept {
  return bl_bit_cast<uint32_t>(a) == bl_bit_cast<uint32_t>(b);
}

template<>
[[nodiscard]]
BL_INLINE_NODEBUG bool bl_equals(const double& a, const double& b) noexcept {
  return bl_bit_cast<uint64_t>(a) == bl_bit_cast<uint64_t>(b);
}
//! \endcond

//! \}
//! \}
#endif

//! \addtogroup bl_containers
//! \{

//! Provides start and end indexes. It has the same semantics as Slices in other programming languages - range is
//! always within [star, end) internal (start is inclusive, end is exclusive). It's used to specify a range of an
//! operation of indexed containers like \ref BLString, \ref BLArray, \ref BLGradient, \ref BLPath, etc...
struct BLRange {
  size_t start;
  size_t end;

#ifdef __cplusplus
  //! \name Construction & Destruction
  //! \{

  [[nodiscard]]
  static BL_INLINE_CONSTEXPR BLRange everything() noexcept { return BLRange{0, SIZE_MAX}; }

  //! \}

  //! \name Overloaded Operators
  //! \{

  [[nodiscard]]
  BL_INLINE_NODEBUG bool operator==(const BLRange& other) const noexcept { return equals(other); }

  [[nodiscard]]
  BL_INLINE_NODEBUG bool operator!=(const BLRange& other) const noexcept { return !equals(other); }

  //! \}

  //! \name Common Functionality
  //! \{

  //! Reset the range to [0, 0).
  BL_INLINE_NODEBUG void reset() noexcept { *this = BLRange{}; }

  //! Reset the range to [start, end).
  BL_INLINE_NODEBUG void reset(size_t r_start, size_t r_end) noexcept { *this = BLRange{r_start, r_end}; }

  //! \}

  //! \name Equality & Comparison
  //! \{

  [[nodiscard]]
  BL_INLINE_NODEBUG bool equals(const BLRange& other) const noexcept {
    return BLInternal::bool_and(bl_equals(start, other.start),
                                bl_equals(end, other.end));
  }

  //! \}
#endif
};

#ifdef __cplusplus

//! Array view of `T`.
//!
//! \note In C mode the type of data used by \ref BLArrayView is `const void*`, thus it has to be retyped to a real
//! type this view points to. There are only few specializations like \ref BLStringView that point to a real type.
template<typename T>
struct BLArrayView {
  const T* data;
  size_t size;

  BL_INLINE_NODEBUG void reset() noexcept { *this = BLArrayView{}; }

  BL_INLINE_NODEBUG void reset(const T* data_in, size_t size_in) noexcept {
    data = data_in;
    size = size_in;
  }

  [[nodiscard]]
  BL_INLINE const T& operator[](size_t index) noexcept {
    BL_ASSERT(index < size);
    return data[index];
  }

  [[nodiscard]]
  BL_INLINE_NODEBUG const T* begin() const noexcept { return data; }

  [[nodiscard]]
  BL_INLINE_NODEBUG const T* end() const noexcept { return data + size; }

  [[nodiscard]]
  BL_INLINE_NODEBUG const T* cbegin() const noexcept { return data; }

  [[nodiscard]]
  BL_INLINE_NODEBUG const T* cend() const noexcept { return data + size; }
};

// In C++ mode these are just typedefs of `BLArrayView<Type>`.

//! View of `char[]` data used by String.
using BLStringView = BLArrayView<char>;

//! View of untyped data.
using BLDataView = BLArrayView<uint8_t>;

#else

#define BL_DEFINE_ARRAY_VIEW(NAME, TYPE) \
  typedef struct {                       \
    const TYPE* data;                    \
    size_t size;                         \
  } NAME

BL_DEFINE_ARRAY_VIEW(BLArrayView, void);
BL_DEFINE_ARRAY_VIEW(BLStringView, char);

typedef BLArrayView BLDataView;

#undef BL_DEFINE_ARRAY_VIEW

#endif

//! \}

#endif // BLEND2D_API_H_INCLUDED
